#pragma once

#include <glad/glad.h>
#include <glm/glm.hpp>

// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum class CameraMovement : GLboolean {
  Forward,
  Backward,
  Left,
  Right
};

// Default camera values
static const float YAW         = -90.0f;
static const float PITCH       =  0.0f;
static const float SPEED       =  2.5f;
static const float SENSITIVITY =  0.1f;
static const float ZOOM        =  45.0f;

class Camera {
 public:

  glm::vec3 position;
  glm::vec3 front;
  glm::vec3 up;
  //
  glm::vec3 right;
  glm::vec3 worldUp;
  // euler Angles
  float yaw;
  float pitch;
  // camera options
  float movementSpeed;
  float mouseSensitivity;
  float zoom;
 public:
  // constructor with vectors
  Camera(glm::vec3 position = glm::vec3(0.f, 0.f, 0.f), glm::vec3 up = glm::vec3(0.f, 1.f, 0.f), float yaw = YAW, float pitch = PITCH);
  // constructor with scalar values
  Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch);

  // returns the view matrix calculated using Euler Angles and the LookAt Matrix
  glm::mat4 viewMatrix();

  // processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
  void processKeyboard(CameraMovement direction);

  // processes input received from a mouse input system. Expects the offset value in both the x and y direction.
  void processMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);

  // processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
  void processMouseScroll(float yoffset);

  void update(float deltaTime);
 private:
  // calculates the front vector from the Camera's (updated) Euler Angles
  void updateCameraVectors();
 private:
  glm::vec3 movement_;
};
